package fi.pakkanen.yarpg.creature;

import java.util.HashMap;
import java.util.Map;

/**
 * The attributes of all creatures in the game.
 * 
 * @author Oliver Michels <oliver.michels@gmx.net>
 * 
 */
public class Attributes {

	private Map<AttributeType, Integer> currentValues;
	private Map<AttributeType, Integer> maxValues;

	/**
	 * Create a new set of attributes for a creature.
	 */
	public Attributes(Map<AttributeType, Integer> maxAttributeValues) {
		maxValues = maxAttributeValues;
		currentValues = new HashMap<AttributeType, Integer>();

		resetAttributes();
	}

	/**
	 * Reset all attributes to their maximum values.
	 */
	public void resetAttributes() {
		for (AttributeType type : AttributeType.values()) {
			currentValues.put(type, getMaxValue(type));
		}
	}

	/**
	 * Get the maximum value for the given attribute type.
	 * 
	 * @param type
	 *            the attribute type
	 * @return the maximum value for the given type
	 * @throws IllegalArgumentException
	 *             is thrown when no attribute of the given type was found
	 */
	protected int getMaxValue(AttributeType type) {
		if (!maxValues.containsKey(type)) {
			throw new IllegalArgumentException("Attribute type " + type + " is unknown for " + this);
		}

		return maxValues.get(type);
	}

	/**
	 * Get the current value of the given attribute type.
	 * 
	 * @param type
	 *            the attribute type
	 * @return the current value of the given attribute type
	 * @throws IllegalArgumentException
	 *             is thrown when no attribute of the given type was found
	 */
	public int getCurrentValue(AttributeType type) {
		if (!currentValues.containsKey(type)) {
			throw new IllegalArgumentException("Attribute type " + type + " is unknown for " + this);
		}

		return currentValues.get(type);
	}

	/**
	 * Update the attribute of the given type by the given value.
	 * 
	 * When the newly calculated value is illegal, that is < 0 or > max value,
	 * the value is set to 0 or max value.
	 * 
	 * @param type
	 *            the attribute type
	 * @param delta
	 *            the delta by which the attribute value should be changed.
	 */
	public void updateCurrentValue(AttributeType type, int delta) {
		if (delta > 0) {
			currentValues.put(type, Math.min((getCurrentValue(type) + delta), getMaxValue(type)));
		} else if (delta < 0) {
			currentValues.put(type, Math.max((getCurrentValue(type) - delta), 0));
		}

	}

	public void increaseMaxValue(AttributeType type) {
		if (!maxValues.containsKey(type)) {
			throw new IllegalArgumentException("Attribute type " + type + " is unknown for " + this);
		}

		maxValues.put(type, getMaxValue(type) + 1);
	}

	/**
	 * Get the current strength.
	 * 
	 * @return the current strength
	 * @see #getCurrentValue(AttributeType)
	 */
	public int getStrength() {
		return getCurrentValue(AttributeType.STRENGTH);
	}

	/**
	 * Get the current dexterity.
	 * 
	 * @return the current dexterity
	 * @see #getCurrentValue(AttributeType)
	 */
	public int getDexterity() {
		return getCurrentValue(AttributeType.DEXTERITY);
	}

	/**
	 * Get the current constitution.
	 * 
	 * @return the current constitution
	 * @see #getCurrentValue(AttributeType)
	 */
	public int getConstitution() {
		return getCurrentValue(AttributeType.CONSTITUTION);
	}

	/**
	 * Get the current intelligence.
	 * 
	 * @return the current intelligence
	 * @see #getCurrentValue(AttributeType)
	 */
	public int getIntelligence() {
		return getCurrentValue(AttributeType.INTELLIGENCE);
	}

	/**
	 * Get the current wisdom.
	 * 
	 * @return the current wisdom
	 * @see #getCurrentValue(AttributeType)
	 */
	public int getWisdom() {
		return getCurrentValue(AttributeType.WISDOM);
	}

	/**
	 * Get the current charisma.
	 * 
	 * @return the current charisma
	 * @see #getCurrentValue(AttributeType)
	 */
	public int getCharisma() {
		return getCurrentValue(AttributeType.CHARISMA);
	}

}
